

#ifndef SM2_H
#define SM2_H

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "XMen_sm3.h"


#ifdef __cplusplus
extern "C"
{
#endif

/**
 * @brief Success return code
 */
#define E_OK 0

/**
 * @brief Error return code
 */
#define E_NOT_OK 1


/**
 * @brief Big number type for SM2 calculations, represented as array of 8 uint64_t
 */
typedef uint64_t SM2_BN[8];

/**
 * @brief SM2 curve order N
 */
extern const SM2_BN SM2_N;

/**
 * @brief Constant value 1 as SM2_BN
 */
extern const SM2_BN SM2_ONE;

/**
 * @brief Size of uint32_t in bytes
 */
#define SM2_uint32_SIZE (4)

/**
 * @brief Return type for standard functions
 */
typedef uint8_t Std_ReturnType;

/**
 * @brief Initialize big number to zero
 */
#define XMen_lib_sm2_bn_init(r)     memset((r), 0, sizeof(SM2_BN))

/**
 * @brief Set big number to zero
 */
#define XMen_lib_sm2_bn_set_zero(r) memset((r), 0, sizeof(SM2_BN))

/**
 * @brief Set big number to one
 */
#define XMen_lib_sm2_bn_set_one(r)  XMen_lib_sm2_bn_set_word((r), 1)

/**
 * @brief Copy big number
 */
#define XMen_lib_sm2_bn_copy(r, a)  memcpy((r), (a), sizeof(SM2_BN))

/**
 * @brief Clear big number (set to zero)
 */
#define XMen_lib_sm2_bn_clean(r)    memset((r), 0, sizeof(SM2_BN))

/**
 * @brief Set field element to zero
 */
#define XMen_lib_sm2_fp_set_zero(r) XMen_lib_sm2_bn_set_zero(r)

/**
 * @brief Set field element to one
 */
#define XMen_lib_sm2_fp_set_one(r)  XMen_lib_sm2_bn_set_one(r)

/**
 * @brief Copy field element
 */
#define XMen_lib_sm2_fp_copy(r, a)  XMen_lib_sm2_bn_copy(r, a)

/**
 * @brief Clear field element
 */
#define XMen_lib_sm2_fp_clean(r)    XMen_lib_sm2_bn_clean(r)

/**
 * @brief Success return code
 */
#define E_OK               0

/**
 * @brief Error return code
 */
#define E_NOK              1

/**
 * @brief Main SM2 signature verification function
 */
int sm2verify_main(
    uint8_t* buf,
    uint32_t buf_length,
    uint8_t* Private_Key,
    uint8_t* Publickey,
    uint8_t* sig,
    uint32_t siglen);

/**
 * @brief Main SM2 signature generation function
 */
Std_ReturnType sm2sign_main(
    uint8_t* buf,
    uint32_t buf_length,
    uint8_t* Private_Key,
    uint8_t* Publickey,
    uint8_t* Sig_Result,
    uint32_t* Sig_Result_Length);

/**
 * @brief Convert big number to byte array
 */
void XMen_lib_sm2_bn_to_bytes(const SM2_BN a, uint8_t out[32]);

/**
 * @brief Convert byte array to big number
 */
void XMen_lib_sm2_bn_from_bytes(SM2_BN r, const uint8_t in[32]);

/**
 * @brief Convert big number to bit string
 */
void XMen_lib_sm2_bn_to_bits(const SM2_BN a, char bits[256]);

/**
 * @brief Set big number to word value
 */
void XMen_lib_sm2_bn_set_word(SM2_BN r, uint32_t a);

/**
 * @brief Add two big numbers
 */
void XMen_lib_sm2_bn_add(SM2_BN r, const SM2_BN a, const SM2_BN b);

/**
 * @brief Subtract two big numbers
 */
void XMen_lib_sm2_bn_sub(SM2_BN ret, const SM2_BN a, const SM2_BN b);

/**
 * @brief Add two field elements
 */
void XMen_lib_sm2_fp_add(SM2_BN r, const SM2_BN a, const SM2_BN b);

/**
 * @brief Subtract two field elements
 */
void XMen_lib_sm2_fp_sub(SM2_BN r, const SM2_BN a, const SM2_BN b);

/**
 * @brief Multiply two field elements
 */
void XMen_lib_sm2_fp_mul(SM2_BN r, const SM2_BN a, const SM2_BN b);

/**
 * @brief Field element exponentiation
 */
void XMen_lib_sm2_fp_exp(SM2_BN r, const SM2_BN a, const SM2_BN e);

/**
 * @brief Double field element
 */
void XMen_lib_sm2_fp_dbl(SM2_BN r, const SM2_BN a);

/**
 * @brief Triple field element
 */
void XMen_lib_sm2_fp_tri(SM2_BN r, const SM2_BN a);

/**
 * @brief Divide field element by 2
 */
void XMen_lib_sm2_fp_div2(SM2_BN r, const SM2_BN a);

/**
 * @brief Negate field element
 */
void XMen_lib_sm2_fp_neg(SM2_BN r, const SM2_BN a);

/**
 * @brief Square field element
 */
void XMen_lib_sm2_fp_sqr(SM2_BN r, const SM2_BN a);

/**
 * @brief Invert field element
 */
void XMen_lib_sm2_fp_inv(SM2_BN r, const SM2_BN a);

/**
 * @brief Type for elements of the finite field Fn
 */
typedef SM2_BN SM2_Fn;

/**
 * @brief Add two Fn elements
 */
void XMen_lib_sm2_fn_add(SM2_Fn r, const SM2_Fn a, const SM2_Fn b);

/**
 * @brief Subtract two Fn elements
 */
void XMen_lib_sm2_fn_sub(SM2_Fn r, const SM2_Fn a, const SM2_Fn b);

/**
 * @brief Multiply two Fn elements
 */
void XMen_lib_sm2_fn_mul(SM2_Fn r, const SM2_Fn a, const SM2_Fn b);

/**
 * @brief Multiply Fn element by word
 */
void XMen_lib_sm2_fn_mul_word(SM2_Fn r, const SM2_Fn a, uint32_t b);

/**
 * @brief Fn element exponentiation
 */
void XMen_lib_sm2_fn_exp(SM2_Fn r, const SM2_Fn a, const SM2_Fn e);

/**
 * @brief Negate Fn element
 */
void XMen_lib_sm2_fn_neg(SM2_Fn r, const SM2_Fn a);

/**
 * @brief Square Fn element
 */
void XMen_lib_sm2_fn_sqr(SM2_Fn r, const SM2_Fn a);

/**
 * @brief Invert Fn element
 */
void XMen_lib_sm2_fn_inv(SM2_Fn r, const SM2_Fn a);

/**
 * @brief Initialize Fn element
 */
#define XMen_lib_sm2_fn_init(r)     XMen_lib_sm2_bn_init(r)

/**
 * @brief Set Fn element to zero
 */
#define XMen_lib_sm2_fn_set_zero(r) XMen_lib_sm2_bn_set_zero(r)

/**
 * @brief Set Fn element to one
 */
#define XMen_lib_sm2_fn_set_one(r)  XMen_lib_sm2_bn_set_one(r)

/**
 * @brief Copy Fn element
 */
#define XMen_lib_sm2_fn_copy(r, a)  XMen_lib_sm2_bn_copy(r, a)

/**
 * @brief Clear Fn element
 */
#define XMen_lib_sm2_fn_clean(r)    XMen_lib_sm2_bn_clean(r)

/**
 * @brief Structure for point in Jacobian coordinates
 */
typedef struct
{
    SM2_BN X; 
    SM2_BN Y; 
    SM2_BN Z; 
} SM2_JACOBIAN_POINT;

/**
 * @brief Initialize Jacobian point
 */    
void XMen_lib_sm2_jacobian_point_init(SM2_JACOBIAN_POINT* R);

/**
 * @brief Set Jacobian point coordinates
 */    
void XMen_lib_sm2_jacobian_point_set_xy(SM2_JACOBIAN_POINT* R, const SM2_BN x, const SM2_BN y);

/**
 * @brief Get Jacobian point coordinates
 */    
void XMen_lib_sm2_jacobian_point_get_xy(const SM2_JACOBIAN_POINT* P, SM2_BN x, SM2_BN y);

/**
 * @brief Negate Jacobian point
 */    
void XMen_lib_sm2_jacobian_point_neg(SM2_JACOBIAN_POINT* R, const SM2_JACOBIAN_POINT* P);

/**
 * @brief Double Jacobian point
 */    
void XMen_lib_sm2_jacobian_point_dbl(SM2_JACOBIAN_POINT* R, const SM2_JACOBIAN_POINT* P);

/**
 * @brief Add Jacobian points
 */    
void XMen_lib_sm2_jacobian_point_add(SM2_JACOBIAN_POINT* R, const SM2_JACOBIAN_POINT* P, const SM2_JACOBIAN_POINT* Q);

/**
 * @brief Subtract Jacobian points
 */    
void XMen_lib_sm2_jacobian_point_sub(SM2_JACOBIAN_POINT* R, const SM2_JACOBIAN_POINT* P, const SM2_JACOBIAN_POINT* Q);

/**
 * @brief Scalar multiplication of Jacobian point
 */    
void XMen_lib_sm2_jacobian_point_mul(SM2_JACOBIAN_POINT* R, const SM2_BN k, const SM2_JACOBIAN_POINT* P);

/**
 * @brief Convert Jacobian point to bytes
 */    
void XMen_lib_sm2_jacobian_point_to_bytes(const SM2_JACOBIAN_POINT* P, uint8_t out[64]);

/**
 * @brief Convert bytes to Jacobian point
 */    
void XMen_lib_sm2_jacobian_point_from_bytes(SM2_JACOBIAN_POINT* P, const uint8_t in[64]);

/**
 * @brief Multiply generator point by scalar
 */    
void XMen_lib_sm2_jacobian_point_mul_generator(SM2_JACOBIAN_POINT* R, const SM2_BN k);

/**
 * @brief Combined scalar multiplication
 */    
void XMen_lib_sm2_jacobian_point_mul_sum(SM2_JACOBIAN_POINT* R, const SM2_BN t, const SM2_JACOBIAN_POINT* P, const SM2_BN s);

/**
 * @brief Set Jacobian point to infinity
 */  
#define XMen_lib_sm2_jacobian_point_set_infinity(R) XMen_lib_sm2_jacobian_point_init(R)

/**
 * @brief Copy Jacobian point
 */
#define XMen_lib_sm2_jacobian_point_copy(R, P)      memcpy((R), (P), sizeof(SM2_JACOBIAN_POINT))

/**
 * @brief Type for big number as byte array
 */
typedef uint8_t lib_sm2_bn_t[32];

/**
 * @brief Structure for point in affine coordinates
 */
typedef struct
{
    uint8_t x[32]; 
    uint8_t y[32]; 
} SM2_POINT;

/**
 * @brief Check if point is on curve
 */
int XMen_lib_sm2_point_is_on_curve(const SM2_POINT *P);

/**
 * @brief Initialize point
 */
#define XMen_lib_sm2_point_init(P)         memset((P), 0, sizeof(SM2_POINT))

/**
 * @brief Set point to infinity
 */
#define XMen_lib_sm2_point_set_infinity(P) XMen_lib_sm2_point_init(P)

/**
 * @brief Maximum size of point encoding
 */
#define SM2_POINT_MAX_SIZE (2 + 65)

/**
 * @brief Structure for SM2 key pair
 */
typedef struct
{
    SM2_POINT public_key;  
    uint8_t private_key[32]; 
} SM2_KEY;

/**
 * @brief Structure for SM2 signature
 */
typedef struct
{
    uint8_t r[32]; 
    uint8_t s[32]; 
} SM2_SIGNATURE;

/**
 * @brief Minimum signature size
 */
#define SM2_MIN_SIGNATURE_SIZE 8

/**
 * @brief Maximum signature size
 */
#define SM2_MAX_SIGNATURE_SIZE 72

/**
 * @brief Signature size constants
 */
enum
{
    SM2_signature_compact_size = 70,  
    SM2_signature_typical_size = 71,  
    SM2_signature_max_size = 72,      
};

/**
 * @brief Default user ID
 */
#define SM2_DEFAULT_ID        "1234567812345678"

/**
 * @brief Length of default user ID
 */
#define SM2_DEFAULT_ID_LENGTH (sizeof(SM2_DEFAULT_ID) - 1)

/**
 * @brief Bit length of default user ID
 */
#define SM2_DEFAULT_ID_BITS   (SM2_DEFAULT_ID_LENGTH * 8)

/**
 * @brief Maximum user ID bits
 */
#define SM2_MAX_ID_BITS       65535

/**
 * @brief Maximum user ID length
 */
#define SM2_MAX_ID_LENGTH     (SM2_MAX_ID_BITS / 8)

/**
 * @brief Structure for signature generation context
 */
typedef struct
{
    LIB_SM3_CTX lib_sm3_ctx;  
    SM2_KEY key;          
} SM2_SIGN_CTX;

/**
 * @brief Initialize signature generation
 */
Std_ReturnType XMen_lib_sm2_sign_init(SM2_SIGN_CTX* ctx, const SM2_KEY* key, const char* id, uint32_t idlen);

/**
 * @brief Update signature generation with data
 */
Std_ReturnType XMen_lib_sm2_sign_update(SM2_SIGN_CTX* ctx, const uint8_t* data, uint32_t datalen);

/**
 * @brief Finish signature generation
 */
Std_ReturnType XMen_lib_sm2_sign_finish(SM2_SIGN_CTX* ctx, uint8_t* sig, uint32_t* siglen);

/**
 * @brief Convert point from octet string
 */
int XMen_lib_sm2_point_from_octets(SM2_POINT *P, const uint8_t *in, uint32_t inlen);

/**
 * @brief Scalar multiplication of point
 */
int XMen_lib_sm2_point_mul(SM2_POINT *R, const uint8_t k[32], const SM2_POINT *P);

/**
 * @brief Initialize signature verification
 */
int XMen_lib_sm2_verify_init(SM2_SIGN_CTX* ctx, const SM2_KEY* key, const char* id, uint32_t idlen);

/**
 * @brief Check if Jacobian point is on curve
 */
int XMen_lib_sm2_jacobian_point_is_on_curve(const SM2_JACOBIAN_POINT *P);

/**
 * @brief Compare big numbers
 */
int XMen_lib_sm2_bn_cmp(const SM2_BN a, const SM2_BN b);

/**
 * @brief Update signature verification with data
 */
int XMen_lib_sm2_verify_update(SM2_SIGN_CTX* ctx, const uint8_t* data, uint32_t datalen);

/**
 * @brief Finish signature verification
 */
int XMen_lib_sm2_verify_finish(SM2_SIGN_CTX* ctx, const uint8_t* sig, uint32_t siglen);

/**
 * @brief Generate random Fn element
 */
int XMen_lib_sm2_fn_rand(SM2_BN r);

/**
 * @brief Check if big number is zero
 */
int XMen_lib_sm2_bn_is_zero(const SM2_BN a);
/**
 * @brief Encrypt data using SM2 public key encryption
 */
int XMen_lib_sm2_encrypt(const uint8_t* key, const uint8_t* in, uint32_t inlen, uint8_t* out, uint32_t* outlen);
/**
 * @brief Decrypt data using SM2 private key
 */
int XMen_lib_sm2_decrypt(const uint8_t* key, const uint8_t* in, uint32_t inlen, uint8_t* out, uint32_t* outlen);
void func_data1(void);

/**
 * @brief Minimum plaintext size
 */
#define SM2_MIN_PLAINTEXT_SIZE 1   

/**
 * @brief Maximum plaintext size
 */
#define SM2_MAX_PLAINTEXT_SIZE 255 

/**
 * @brief Structure for SM2 ciphertext
 */
typedef struct
{
    SM2_POINT point;            
    uint8_t hash[32];           
    uint8_t ciphertext_size;    
    uint8_t ciphertext[SM2_MAX_PLAINTEXT_SIZE]; 
} SM2_CIPHERTEXT;

/**
 * @brief Ciphertext size constants
 */
enum
{
    SM2_ciphertext_compact_point_size = 68,  
    SM2_ciphertext_typical_point_size = 69,  
    SM2_ciphertext_max_point_size = 70,      
};

#ifdef __cplusplus
}
#endif
#endif
